unit QBDb2Window;
{$I QBuilderVerCtrl.inc}
interface

uses
  {$IFDEF VCL16}
    Winapi.Windows,
    System.Classes,
    Vcl.Controls,
    Vcl.StdCtrls,
    Vcl.ComCtrls,
  {$ELSE}
    Windows,
    Classes,
    Controls,
    StdCtrls,
    ComCtrls,
  {$ENDIF}
  QBWindow,
  QBParser,
  QBStringTypes;

const
  Db2SQLKeywords =
    { db2 specific }
  'ADD,AFTER,ALIAS,ALL,ALLOCATE,ALLOW,ALTER,AND,ANY,APPLICATION,AS,' +
    'ASSOCIATE,ASUTIME,AUDIT,AUTHORIZATION,AUX,AUXILIARY,BEFORE,BEGIN,' +
    'BETWEEN,BINARY, BUFFERPOOL,BY,CACHE,CALL,CALLED,CAPTURE,CARDINALITY,' +
    'CASCADED,CASE,CAST,' +
    'CCSID,CHAR,CHARACTER,CHECK,CLOSE,CLUSTER,COLLECTION,COLLID,COLUMN,' +
    'COMMENT,COMMIT,CONCAT,CONDITION,CONNECT,CONNECTION,CONSTRAINT,CONTAINS,' +
    'CONTINUE,CREATE,CROSS,CURRENT,CURRENT_DATE,' +
    'CURRENT_LC_CTYPE,CURRENT_PATH,CURRENT_SERVER,CURRENT_TIME,' +
    'CURRENT_TIMESTAMP,CURRENT_TIMEZONE,CURRENT_USER,CURSOR,CYCLE,' +
    'DATA,DATABASE,DAY,DAYS,DB2GENERAL,DB2GENRL,DB2SQL,DBINFO,DECLARE,' +
    'DEFAULT,DEFAULTS,DEFINITION,DELETE,DESCRIPTOR,DETERMINISTIC,' +
    'DISALLOW,DISCONNECT,DISTINCT,DO,DOUBLE,DROP,DSNHATTR,DSSIZE,DYNAMIC,' +
    'EACH,EDITPROC,ELSE,ELSEIF,ENCODING,END,END-EXEC,END-EXEC1,ERASE,' +
    'ESCAPE,EXCEPT,EXCEPTION,EXCLUDING,EXECUTE,EXISTS,EXIT,EXTERNAL,' +
    'FENCED,FETCH,FIELDPROC,FILE,FINAL,FOR,FOREIGN,FREE,FROM,FULL,FUNCTION,' +
    'GENERAL,GENERATED,GET,GLOBAL,GO,GOTO,GRANT,GRAPHIC,GROUP,HANDLER,HAVING,' +
    'HOLD,HOUR,HOURS,IDENTITY,IF,IMMEDIATE,IN,INCLUDING,INCREMENT,INDEX,' +
    'INDICATOR,INHERIT,INNER,INOUT,INSENSITIVE,INSERT,INTEGRITY,INTO,IS,' +
    'ISOBID,ISOLATION,ITERATE,JAR,JAVA,JOIN,KEY,LABEL,LANGUAGE,LC_CTYPE,' +
    'LEAVE,LEFT,LIKE,LINKTYPE,LOCAL,LOCALE,LOCATOR,LOCATORS,LOCK,LOCKMAX,' +
    'LOCKSIZE,LONG,LOOP,MAXVALUE,MICROSECOND,MICROSECONDS,MINUTE,MINUTES,' +
    'MINVALUE,MODE,MODIFIES,MONTH,MONTHS,NEW,NEW_TABLE,NO,NOCACHE,NOCYCLE,' +
    'NODENAME,NODENUMBER,NOMAXVALUE,NOMINVALUE,NOORDER,NOT,NULL,NULLS,' +
    'NUMPARTS,OBID,OF,OLD,OLD_TABLE,ON,OPEN,OPTIMIZATION,OPTIMIZE,OPTION,' +
    'OR,ORDER,OUT,OUTER,OVERRIDING,PACKAGE,PARAMETER,PART,PARTITION,PATH,' +
    'PIECESIZE,PLAN,POSITION,PRECISION,PREPARE,PRIMARY,PRIQTY,PRIVILEGES,' +
    'PROCEDURE,PROGRAM,PSID,QUERYNO,READ,READS,RECOVERY,REFERENCES,' +
    'REFERENCING,RELEASE,RENAME,REPEAT,RESET,RESIGNAL,RESTART,RESTRICT,' +
    'RESULT,RESULT_SET_LOCATOR,RETURN,RETURNS,REVOKE,RIGHT,ROLLBACK,ROUTINE,' +
    'ROW,ROWS,RRN,RUN,SAVEPOINT,SCHEMA,SCRATCHPAD,SECOND,SECONDS,SECQTY,' +
    'SECURITY,SELECT,SENSITIVE,SET,SIGNAL,SIMPLE,SOME,SOURCE,SPECIFIC,SQL,' +
    'SQLID,STANDARD,START,STATIC,STAY,STOGROUP,STORES,STYLE,SUBPAGES,' +
    'SUBSTRING,SYNONYM,SYSFUN,SYSIBM,SYSPROC,SYSTEM,TABLE,TABLESPACE,THEN,' +
    'TO,TRANSACTION,TRIGGER,TRIM,TYPE,UNDO,UNION,UNIQUE,UNTIL,UPDATE,USAGE,' +
    'USER,USING,VALIDPROC,VALUES,VARIABLE,VARIANT,VCAT,VIEW,VOLUMES,WHEN,' +
    'WHERE,WHILE,WITH,WLM,WRITE,YEAR,YEARS' +
    { sql99 keywords }
  'ABSOLUTE,ACTION,ADMIN,AGGREGATE,ARE,ARRAY,ASC,ASSERTION,AT,BIT,BLOB,' +
    'BOOLEAN,BOTH,BREADTH,CASCADE,CATALOG,CLASS,CLOB,COLLATE,COLLATION,' +
    'COMPLETION,CONSTRAINTS,CONSTRUCTOR,CORRESPONDING,CUBE,CURRENT_ROLE,' +
    'DATE,DEALLOCATE,DEC,DECIMAL,DEFERRABLE,DEFERRED,DEPTH,DEREF,DESC,' +
    'DESCRIBE,DESTROY,DESTRUCTOR,DIAGNOSTICS,DICTIONARY,DOMAIN,EQUALS,' +
    'EVERY,EXEC,FALSE,FIRST,FLOAT,FOUND,GROUPING,HOST,IGNORE,INITIALIZE,' +
    'INITIALLY,INPUT,INT,INTEGER,INTERSECT,INTERVAL,LARGE,LAST,LATERAL,' +
    'LEADING,LESS,LEVEL,LIMIT,LOCALTIME,LOCALTIMESTAMP,MAP,MATCH,MODIFY,' +
    'MODULE,NAMES,NATIONAL,NATURAL,NCHAR,NCLOB,NEXT,NONE,NUMERIC,OBJECT,' +
    'OFF,ONLY,OPERATION,ORDINALITY,OUTPUT,PAD,PARAMETERS,PARTIAL,POSTFIX,' +
    'PREFIX,PREORDER,PRESERVE,PRIOR,PUBLIC,REAL,RECURSIVE,REF,RELATIVE,' +
    'ROLE,ROLLUP,SCOPE,SCROLL,SEARCH,SECTION,SEQUENCE,SESSION,SESSION_USER,' +
    'SETS,SIZE,SMALLINT,SPACE,SPECIFICTYPE,SQLEXCEPTION,SQLSTATE,SQLWARNING,' +
    'STATE,STATEMENT,STRUCTURE,SYSTEM_USER,TEMPORARY,TERMINATE,THAN,TIME,' +
    'TIMESTAMP,TIMEZONE_HOUR,TIMEZONE_MINUTE,TRAILING,TRANSLATION,TREAT,' +
    'TRUE,UNDER,UNKNOWN,UNNEST,VALUE,VARCHAR,VARYING,WHENEVER,WITHOUT,' +
    'WORK,ZONE';

  Db2SQLFunctions =
    'ABS,ABSVAL,ABS,ABSVAL,ACOS,ASCII,ASIN,ATAN,ATAN2,ATANH,AVG,' +
    'BIGINT,BLOB,CEIL,CEILING,CHAR,CHAR,CHR,CLOB,COALESCE,CONCAT,||,' +
    'CORRELATION,CORR,COS,COSH,COT,COUNT,COUNT_BIG,COVARIANCE,COVAR,DATE,' +
    'DAY,DAYNAME,DAYOFWEEK,DAYOFWEEK_ISO,DAYOFYEAR,DAYS,DBCLOB,' +
    'DBPARTITIONNUM,DECIMAL,DEC,DECIMAL,DEC,DECRYPT_BIN,DECRYPT_CHAR,' +
    'DEGREES,DEREF,DIFFERENCE,DIGITS,DLCOMMENT,DLLINKTYPE,DLNEWCOPY,' +
    'DLPREVIOUSCOPY,DLREPLACECONTENT,DLURLCOMPLETE,DLURLCOMPLETEONLY,' +
    'DLURLCOMPLETEWRITE,DLURLPATH,DLURLPATHONLY,DLURLPATHWRITE,DLURLSCHEME,' +
    'DLURLSERVER,DLVALUE,DOUBLE,DOUBLE_PRECISION,DOUBLE,ENCRYPT,' +
    'EVENT_MON_STATE,EXP,FLOAT,FLOOR,GETHINT,GENERATE_UNIQUE,GET_ROUTINE_SAR,' +
    'GRAPHIC,GROUPING,HASHEDVALUE,HEX,HOUR,IDENTITY_VAL_LOCAL,INSERT,' +
    'INTEGER,INT,JULIAN_DAY,LCASE,LOWER,LCASE,LEFT,LENGTH,LN,' +
    'LOCATE,LOG,LOG10,LONG_VARCHAR,LONG_VARGRAPHIC,LTRIM,LTRIM,MAX,' +
    'MICROSECOND,MIDNIGHT_SECONDS,MIN,MINUTE,MOD,MONTH,MONTHNAME,MQPUBLISH,' +
    'MQREAD,MQREADALL,MQRECEIVE,MQRECEIVEALL,MQSEND,MQSUBSCRIBE,' +
    'MQUNSUBSCRIBE,MULTIPLY_ALT,NULLIF,POSSTR,POWER,PUT_ROUTINE_SAR,' +
    'QUARTER,RADIANS,RAISE_ERROR,RAND,REAL,REC2XML,REGR_AVGX,REGR_AVGY,' +
    'REGR_COUNT,REGR_INTERCEPT,REGR_ICPT,REGR_R2,REGR_SLOPE,REGR_SXX,' +
    'REGR_SXY,REGR_SYY,REPEAT,REPLACE,RIGHT,ROUND,RTRIM,RTRIM,SECOND,SIGN,' +
    'SIN,SINH,SMALLINT,SOUNDEX,SPACE,SQLCACHE_SNAPSHOT,SQRT,STDDEV,SUBSTR,' +
    'SUM,TABLE_NAME,TABLE_SCHEMA,TAN,TANH,TIME,TIMESTAMP,TIMESTAMP_FORMAT,' +
    'TIMESTAMP_ISO,TIMESTAMPDIFF,TO_CHAR,TO_DATE,TRANSLATE,TRUNC,TRUNCATE,' +
    'TYPE_ID,TYPE_NAME,TYPE_SCHEMA,UCASE,UPPER,UCASE,VALUE,VARCHAR,' +
    'VARCHAR_FORMAT,VARGRAPHIC,VARIANCE,VAR,WEEK,WEEK_ISO,YEAR';

  Db2SQLOperations = '+,-,*,/,|';
  Db2SQLCompareOperators = '=,<>,<,<=,>,>=,!=,!>,!<," LIKE "';
  Db2SQLJoinOperators = '=,<>,<,<=,>,>=,!=,!>,!<'; //," LIKE "';

  Db2SQLBoolFalse = 'False';
  Db2SQLBoolTrue = 'True';

type

  TQBDb2SQLOptions = class(TPersistent)
  private
    FLimitRows: integer;
    FParser: TQBSelectParser;
    function GetLimitScript: aqbString;
    function GetDistinctScript: aqbString;
  public
    constructor Create(AParser: TQBSelectParser);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    procedure Clear;
    property LimitRows: integer read FLimitRows write FLimitRows;
    property LimitScript: aqbString read GetLimitScript;
    property DistinctScript: aqbString read GetDistinctScript;
    property Parser: TQBSelectParser read FParser;
  end;

  TQBDb2SQLScanner = class(TQBSQLScanner)
  private
    FUseNamespaces: boolean;
  protected
    function GetIdentQuote: aqbChar; override;
    function GetProcessAliases: boolean; override;
//    function IsAlpha(Ch: aqbChar): boolean; override;
    function IsQuote(Ch: aqbChar): boolean; override;
    function GetCommaKeywords: aqbString; override;
    function GetCommaFunctions: aqbString; override;
    function GetCommaOperations: aqbString; override;
    function GetCommaCompareOperators: aqbString; override;
    function GetCommaJoinOperators: aqbString; override;
    function ProcessIdent(const S: aqbString): aqbString; override;
    procedure DefineBooleans; override;
    function GetFormatTokenIdent(const Ident: aqbString;
      const Quoted: boolean): aqbString; override;
  public
    constructor Create; override;
    function QuoteName(const S: aqbString): aqbString; override;
    function ProcessName(const S: aqbString): aqbString; override;
    function IsIdentQuote(Ch: aqbChar): boolean; override;
    function NeedQuotes(const Ident: aqbString): boolean; override;
    property UseNamespaces: boolean read FUseNamespaces write FUseNamespaces
      default true;
  end;

  TQBDb2SelectParser = class(TQBSelectParser)
  private
    FDb2SQLOptions: TQBDb2SQLOptions;
    procedure SetDb2SQLOptions(const Value: TQBDb2SQLOptions);
  protected
    function CreateScanner: TQBSQLScanner; override;
    function GetExpression: aqbString; override;
    procedure DefineOperators; override;
    procedure DoParseSelectClause; override;
    procedure DoParseDistinct; virtual;
    procedure DoParseAppendix; override;
    function GetTableNameAndAliasDelim: aqbString; override;
    function GetCaseSensitiveIdentifiers: boolean; override;
  public
    constructor Create(AParent: TPersistent); override;
    destructor Destroy; override;
    procedure Clear; override;
    property Db2SQLOptions: TQBDb2SQLOptions read FDb2SQLOptions
      write SetDb2SQLOptions;
  end;

  TDb2QueryBuilder = class(TFullQueryBuilder {TCustomQueryBuilder})
  private
    function GetUseNamespaces: boolean;
    procedure SetUseNamespaces(const Value: boolean);
  public
    constructor Create(AOwner: TComponent); override;
    function AddQueryBuilder(AddUnion: boolean): TCustomQueryBuilder; override;
    function CreateParser(AParent: TPersistent): TQBSelectParser; override;
  published
    property About;
    property Align;
    property Aggregates;
    property Functions;
    property Keywords;
    property Operators;
    property Options;
    property Palette;
    property ScriptFormat;
    property Storage;
    property Style;
    property TabHeight;
    property UseNamespaces: boolean read GetUseNamespaces write SetUseNamespaces
      default true;
    property VisibleTabs;
    property _Version;
    // ayz
    property WorkAreaPopupMenu;
    property TabsPopupMenu;
    // \ayz

    property OnStartDrag;
    property OnDragOver;
    property OnDragDrop;
    property OnEndDrag;
    {$IFNDEF EC_UNICODE}
    property OnGetTableFields;
    property OnParserError;
    {$ELSE}
    property OnGetTableFieldsW;
    property OnParserErrorW;
    {$ENDIF}
    property OnAddRemoveTable;
    property OnAddRemoveLink;
    property OnEnterProcParameter;
  end;

implementation

uses
  {$IFDEF VCL16}
    System.SysUtils,
  {$ELSE}
    SysUtils,
  {$ENDIF}
  QBUtils, QBResource;

const
  sSelect = 'SELECT';
  sLimitFrm = 'FETCH FIRST %d ROWS ONLY';
  sFetch = 'FETCH';
  sFirst = 'FIRST';
  sRow = 'ROW';
  sRows = 'ROWS';
  sOnly = 'ONLY';

  sDistinct = 'DISTINCT';
  sOn = 'ON';

  { TQBDb2SQLScanner }

constructor TQBDb2SQLScanner.Create;
begin
  inherited;
  FUseNamespaces := true;
  EnableNameSpaces := true;
end;

procedure TQBDb2SQLScanner.DefineBooleans;
begin
  Booleans[False] := Db2SQLBoolFalse;
  Booleans[True] := Db2SQLBoolTrue;
end;

function TQBDb2SQLScanner.GetCommaCompareOperators: aqbString;
begin
  Result := Db2SQLCompareOperators;
end;

function TQBDb2SQLScanner.GetCommaFunctions: aqbString;
begin
  Result := Db2SQLFunctions;
end;

function TQBDb2SQLScanner.GetCommaJoinOperators: aqbString;
begin
  Result := Db2SQLJoinOperators;
end;

function TQBDb2SQLScanner.GetCommaKeywords: aqbString;
begin
  Result := Db2SQLKeywords;
end;

function TQBDb2SQLScanner.GetCommaOperations: aqbString;
begin
  Result := Db2SQLOperations;
end;

function TQBDb2SQLScanner.GetFormatTokenIdent(const Ident: aqbString;
  const Quoted: boolean): aqbString;
begin
  Result := Ident;
  if QuoteIdentifiers and Quoted and
    (Length(Ident) > 1) and (not IsIdentQuote(Ident[1]) or not
    (Ident[Length(Ident)] = GetQuotePair(Ident[1]))) then
    Result := QuoteString(Ident, IdentQuote, GetQuotePair(IdentQuote));
  if not Quoted then
    Result := QBUpperCase(Ident);
end;

function TQBDb2SQLScanner.GetIdentQuote: aqbChar;
begin
  Result := '"';
end;

function TQBDb2SQLScanner.GetProcessAliases: boolean;
begin
  Result := True;
end;
(*
function TQBDb2SQLScanner.IsAlpha(Ch: aqbChar): boolean;
begin
  Result := Ch in ['a'..'z', 'A'..'Z'];
end;
*)
function TQBDb2SQLScanner.IsIdentQuote(Ch: aqbChar): boolean;
begin
  Result := Ch = '"';
end;

function TQBDb2SQLScanner.IsQuote(Ch: aqbChar): boolean;
begin
  Result := Ch = '''';
end;

function TQBDb2SQLScanner.NeedQuotes(const Ident: aqbString): boolean;
begin
  if (Length(Ident) > 1) and IsIdentQuote(Ident[1]) and
    IsIdentQuote(Ident[Length(Ident)]) then
    Result := false
  else
    Result := IsKeyword(Ident) or IsFunction(Ident) or
      (inherited NeedQuotes(Ident)) or (Ident <> QBUpperCase(Ident));
end;

function TQBDb2SQLScanner.ProcessIdent(const S: aqbString): aqbString;
begin
  if (Length(S) > 1) and IsIdentQuote(S[1]) and IsIdentQuote(S[Length(S)]) and
  (S[1] = S[Length(S)]) then
    Result := Copy(S, 2, Length(S) - 2)
  else
    Result := QBUpperCase(S);
  Result := inherited ProcessIdent(S);
end;

function TQBDb2SQLScanner.ProcessName(const S: aqbString): aqbString;
begin
  Result := inherited ProcessName(S);
end;

function TQBDb2SQLScanner.QuoteName(const S: aqbString): aqbString;
begin
  Result := inherited QuoteName(S);
end;

{ TQBDb2SQLOptions }

procedure TQBDb2SQLOptions.Assign(Source: TPersistent);
begin
  if Source is TQBDb2SQLOptions then
  begin
    FLimitRows := TQBDb2SQLOptions(Source).LimitRows;
  end
  else
    inherited;
end;

procedure TQBDb2SQLOptions.Clear;
begin
  FLimitRows := 0;
end;

constructor TQBDb2SQLOptions.Create(AParser: TQBSelectParser);
begin
  inherited Create;
  FParser := AParser;
end;

destructor TQBDb2SQLOptions.Destroy;
begin
  inherited;
end;

function TQBDb2SQLOptions.GetDistinctScript: aqbString;
begin
  Result := '';
  if Assigned(FParser) and FParser.Distinct then
    Result := sDistinct + ' ';
end;

function TQBDb2SQLOptions.GetLimitScript: aqbString;
var
  S: aqbString;
begin
  Result := '';
  if FLimitRows > 0 then
  begin
    S := sLimitFrm;
    if Assigned(FParser) then
      S := FParser.ProcessKeyword(S);
    Result := qbFormat(S, [FLimitRows]);
  end;
  if Result <> '' then
    Result := Result + sEOL;
end;

{ TQBDb2SelectParser }

procedure TQBDb2SelectParser.Clear;
begin
  inherited;
  FDb2SQLOptions.Clear;
end;

constructor TQBDb2SelectParser.Create(AParent: TPersistent);
begin
  inherited Create(AParent);
  FDb2SQLOptions := TQBDb2SQLOptions.Create(Self);
end;

function TQBDb2SelectParser.CreateScanner: TQBSQLScanner;
begin
  Result := TQBDb2SQLScanner.Create;
end;

procedure TQBDb2SelectParser.DefineOperators;
var
  Operator: TQBOperator;
begin
  Operators.Clear;

  Operator := Operators.Add;
  Operator.Name := '=';
  Operator.Caption := '=';

  Operator := Operators.Add;
  Operator.Name := '<>';
  Operator.Caption := '<>';

  Operator := Operators.Add;
  Operator.Name := '<';
  Operator.Caption := '<';

  Operator := Operators.Add;
  Operator.Name := '>';
  Operator.Caption := '>';

  Operator := Operators.Add;
  Operator.Name := '<=';
  Operator.Caption := '<=';

  Operator := Operators.Add;
  Operator.Name := '>=';
  Operator.Caption := '>=';

  Operator := Operators.Add;
  Operator.Name := '!=';
  Operator.Caption := '!=';

  Operator := Operators.Add;
  Operator.Name := '!>';
  Operator.Caption := '!>';

  Operator := Operators.Add;
  Operator.Name := '!<';
  Operator.Caption := '!<';

  Operator := Operators.Add;
  Operator.Name := 'LIKE';
  Operator.Caption := 'LIKE';

  Operator := Operators.Add;
  Operator.Name := 'NOT LIKE';
  Operator.Caption := 'NOT LIKE';

  Operator := Operators.Add;
  Operator.Name := 'IN';
  Operator.Caption := 'IN';
  Operator.Prefix := '(';
  Operator.Postfix := ')';

  Operator := Operators.Add;
  Operator.Name := 'NOT IN';
  Operator.Caption := 'NOT IN';
  Operator.Prefix := '(';
  Operator.Postfix := ')';

  Operator := Operators.Add;
  Operator.Name := 'BETWEEN';
  Operator.Caption := 'BETWEEN';
  Operator.Relate := 'AND';
  Operator.Count := 2;

  Operator := Operators.Add;
  Operator.Name := 'NOT BETWEEN';
  Operator.Caption := 'NOT BETWEEN';
  Operator.Relate := 'AND';
  Operator.Count := 2;

  Operator := Operators.Add;
  Operator.Name := 'IS NULL';
  Operator.Caption := 'IS NULL';
  Operator.Count := 0;

  Operator := Operators.Add;
  Operator.Name := 'IS NOT NULL';
  Operator.Caption := 'IS NOT NULL';
  Operator.Count := 0;
end;

destructor TQBDb2SelectParser.Destroy;
begin
  FDb2SQLOptions.Free;
  inherited;
end;

procedure TQBDb2SelectParser.DoParseAppendix;
var
  Limit: integer;
  S: TQBSelectState;
begin
  S := ssError;
  if QBCompareText(Scanner.Token, sFetch) = 0 then
  begin
    Scanner.GetNextToken;
    if QBCompareText(Scanner.Token, sFirst) = 0 then
    begin
      Scanner.GetNextToken;
      if tkInteger in Scanner.TokenKind then
      begin
        Limit := StrToInt(Scanner.Token);
        Scanner.GetNextToken;
        if ((QBCompareText(Scanner.Token, sRow) = 0) or
          (QBCompareText(Scanner.Token, sRows) = 0)) and
          (QBCompareText(Scanner.GetNextToken, sOnly) = 0) then
        begin
          FDb2SQLOptions.LimitRows := Limit;
          Scanner.GetNextToken;
          S := State;
        end;
      end
    end;
  end;
  State := S;
end;

procedure TQBDb2SelectParser.DoParseDistinct;
begin
  //
end;

procedure TQBDb2SelectParser.DoParseSelectClause;
begin
  inherited;
  { if State = ssError then
   begin
     if CompareText(Scanner.Token, sOn) = 0 then
       DoParseDistinct
     else
       State := ssError;
   end;}
end;

function TQBDb2SelectParser.GetCaseSensitiveIdentifiers: boolean;
begin
  Result := true;
end;

function TQBDb2SelectParser.GetExpression: aqbString;
begin
  {
  Result := TableDefs.Script;
  if Result <> '' then
    Result := ProcessKeyWord(sSelect) + ' ' + FDb2SQLOptions.DistinctScript +
      Result + WhereItems.Script + GroupByItems.Script + HavingItems.Script +
      OrderByItems.Script + FDb2SQLOptions.LimitScript;
   }
  Result := TableDefs.Script;
  if Result <> '' then
    case TypeQuery of
      tqSelect: Result := ProcessKeyWord(sSelect) + ' ' + FDb2SQLOptions.DistinctScript +
        Result + WhereItems.Script + GroupByItems.Script + HavingItems.Script +
          OrderByItems.Script + FDb2SQLOptions.LimitScript;
      tqInsert: Result := ProcessKeyword('INSERT') + ' ' + ProcessKeyword('INTO') +
        Result + ValuesItems.Script;
      tqUpdate: Result := ProcessKeyWord('UPDATE') + ' ' + Result + WhereItems.Script;
      tqDelete: Result := ProcessKeyWord('DELETE') + ' ' + Result + WhereItems.Script;
    end;
end;

function TQBDb2SelectParser.GetTableNameAndAliasDelim: aqbString;
begin
  Result := ' AS ';
end;

procedure TQBDb2SelectParser.SetDb2SQLOptions(const Value: TQBDb2SQLOptions);
begin
  if FDb2SQLOptions <> Value then
    FDb2SQLOptions.Assign(Value);
end;

{ TDb2QueryBuilder }

constructor TDb2QueryBuilder.Create(AOwner: TComponent);
begin
  inherited;
end;

function TDb2QueryBuilder.AddQueryBuilder(AddUnion: boolean): TCustomQueryBuilder;
begin
  Result := inherited AddQueryBuilder(AddUnion);
  TQBDb2SQLScanner(QueryBuilders[QueryBuilders.Count - 1].Data.Parser.Scanner).UseNamespaces := TQBDb2SQLScanner(Parser.Scanner).UseNamespaces;
end;

function TDb2QueryBuilder.CreateParser(AParent: TPersistent): TQBSelectParser;
begin
  Result := TQBDb2SelectParser.Create(AParent);
end;

function TDb2QueryBuilder.GetUseNamespaces: boolean;
begin
  Result := TQBDb2SQLScanner(Parser.Scanner).UseNamespaces;
end;

procedure TDb2QueryBuilder.SetUseNamespaces(const Value: boolean);
var
  I: integer;
begin
  //  TQBDb2SQLScanner(Parser.Scanner).UseNamespaces := Value;
  if TQBDb2SQLScanner(Parser.Scanner).UseNamespaces <> Value then
  begin
    TQBDb2SQLScanner(Parser.Scanner).UseNamespaces := Value;
    for I := 0 to QueryBuilders.Count - 1 do
      TQBDb2SQLScanner(QueryBuilders[I].Data.Parser.Scanner).UseNamespaces := Value;
  end;
end;

end.
